package com.isyscore.os.metadata.service.diop;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.thread.ExecutorBuilder;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.isyscore.boot.login.LoginUserManager;
import com.isyscore.boot.login.LoginUserManagerImpl;
import com.isyscore.os.core.exception.DataFactoryException;
import com.isyscore.os.core.exception.ErrorCode;
import com.isyscore.os.metadata.model.dto.diop.DiopResourceDto;
import com.isyscore.os.metadata.model.dto.diop.DiopResultNotifyDto;
import com.isyscore.os.metadata.model.entity.Datamodel;
import com.isyscore.os.metadata.model.entity.MetricGroup;
import com.isyscore.os.metadata.service.impl.DatamodelService;
import com.isyscore.os.metadata.service.impl.MetricGroupService;
import com.isyscore.os.permission.entity.LoginVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import static com.isyscore.os.metadata.service.diop.DiopConstant.*;
import static java.util.Collections.emptyList;

@Service
@Slf4j
public class DiopApiService {

    @Autowired
    private DiopNotifyService diopNotifyService;

    @Autowired
    private ImportService importService;

    @Autowired
    private ExportService exportService;

    @Autowired
    private DatamodelService datamodelService;

    @Autowired
    private MetricGroupService metricGroupService;

    @Value("${diop.app-code}")
    private String appCode;

    @Value("${diop.service-id}")
    private String serviceId;

    @Autowired
    private LoginUserManager loginUserManager;
    //导入导出的锁，控制导入导出过程不会同时进行
    private final ReentrantLock diopLock = new ReentrantLock();

    private ExecutorService diopExecutor = ExecutorBuilder.create()
            .setCorePoolSize(1)
            .setMaxPoolSize(1)
            .build();

    public boolean importResource(String token, String dirPath, String callbackUrl) {
        if (diopLock.isLocked()) {
            return false;
        }
//        if(!tenantIdCheck(dirPath)){
//            throw new DataFactoryException(ErrorCode.ERROR_TENANT_INFO);
//        }
        String tenantId=loginUserManager.getCurrentTenantId();
        LoginVO loginVO=loginUserManager.getCurrentLoginUser();
        diopExecutor.submit(() -> {
            Thread.currentThread().setName("metric-resources-import-" + new DateTime().toString("yyyyMMddHHmmss"));
            //异步线程池，需要重新设置一下线程ThreadLocal的用户信息
            ((LoginUserManagerImpl)loginUserManager).setThreadLocalLoginUser(loginVO);
            diopLock.lock();
            try {
                importService.doImportResource(dirPath);
                DiopResultNotifyDto notify = new DiopResultNotifyDto();
                notify.setServiceId(serviceId);
                notify.setAppCode(appCode);
                notify.setStatus(200);
                notify.setDirPath(dirPath);
                diopNotifyService.notifyResult(callbackUrl, token, notify,tenantId);
                log.info("数据导入成功，导入数据的存储目录为：" + dirPath);
            } catch (Exception e) {
                log.error("DIOP导入数据失败", e);
                DiopResultNotifyDto notify = new DiopResultNotifyDto();
                notify.setServiceId(serviceId);
                notify.setAppCode(appCode);
                notify.setStatus(500);
                notify.setDirPath(dirPath);
                notify.setMessage("导入失败：" + e.getMessage());
                diopNotifyService.notifyResult(callbackUrl, token, notify,tenantId);
                throw new DataFactoryException(ErrorCode.DIOP_IMPORT_ERROR);
            } finally {
                diopLock.unlock();
            }
        });
        return true;
    }

    public boolean exportResources(String token, List<DiopResourceDto> resources, String callbackUrl) {
        if (diopLock.isLocked()) {
            return false;
        }
        String tenantId=loginUserManager.getCurrentTenantId();
        LoginVO loginVO=loginUserManager.getCurrentLoginUser();
        diopExecutor.submit(() -> {
            Thread.currentThread().setName("metric-resources-export-" + new DateTime().toString("yyyyMMddHHmmss"));
            //异步线程池，需要重新设置一下线程ThreadLocal的用户信息
            ((LoginUserManagerImpl)loginUserManager).setThreadLocalLoginUser(loginVO);
            diopLock.lock();
            try {
                String exportDir = exportService.doExport(resources,tenantId);
                //通过回调地址通知DIOP导入结果
                DiopResultNotifyDto notify = new DiopResultNotifyDto();
                notify.setServiceId(serviceId);
                notify.setAppCode(appCode);
                notify.setStatus(200);
                notify.setDirPath(exportDir);
                diopNotifyService.notifyResult(callbackUrl, token, notify,tenantId);
                log.info("数据导出成功，导出数据的存储目录为：" + exportDir);
            } catch (Exception e) {
                log.error("DIOP导出数据失败", e);
                DiopResultNotifyDto notify = new DiopResultNotifyDto();
                notify.setServiceId(serviceId);
                notify.setAppCode(appCode);
                notify.setStatus(500);
                notify.setMessage("导出失败:" + e.getMessage());
                diopNotifyService.notifyResult(callbackUrl, token, notify,tenantId);
            } finally {
                diopLock.unlock();
            }
        });
        return true;
    }

    public List<DiopResourceDto> getDIOPResources() {
        List<Datamodel> datamodels = datamodelService.list();
        if (datamodels == null || datamodels.isEmpty()) {
            return emptyList();
        }
        //构造数据模型的资源
        DiopResourceDto datamodelTopResource = new DiopResourceDto();
        datamodelTopResource.setDesc("数据模型");
        datamodelTopResource.setName(DATAMODEL_RESOURCE_NAME);
        List<DiopResourceDto> datamodelResources = datamodels.stream().map((dm) -> {
            DiopResourceDto datamodelRes = new DiopResourceDto();
            datamodelRes.setName(String.valueOf(dm.getId()));
            datamodelRes.setDesc(dm.getName());
            return datamodelRes;
        }).collect(Collectors.toList());
        datamodelTopResource.setExtra(datamodelResources);
        //构造数据指标的资源,资源粒度为指标分组
        List<MetricGroup> metricGroups = metricGroupService.list();
        DiopResourceDto metricTopResource = new DiopResourceDto();
        metricTopResource.setDesc("数据指标");
        metricTopResource.setName(METRIC_RESOURCE_NAME);
        List<DiopResourceDto> metricResources = metricGroups.stream().map((group) -> {
            DiopResourceDto metricRes = new DiopResourceDto();
            metricRes.setName(String.valueOf(group.getId()));
            metricRes.setDesc(group.getGroupName());
            return metricRes;
        }).collect(Collectors.toList());
        metricTopResource.setExtra(metricResources);
        DiopResourceDto sqlQueryResource = new DiopResourceDto();
        sqlQueryResource.setDesc("SQL查询");
        sqlQueryResource.setName(SQL_QUERY_RESOURCE_NAME);
        return Lists.newArrayList(datamodelTopResource, metricTopResource,sqlQueryResource);
    }

    public boolean tenantIdCheck(String path){
       return StrUtil.contains(path,loginUserManager.getCurrentTenantId());
    }
}
